日志

使用 Kanzi 日志系统打印消息到您目标设备中的 日志 (Log) 窗口、Kanzi 调试控制台、标准输出和系统日志。例如,使用日志查找 Kanzi 应用程序中的问题,并通知用户您应用程序的状态。

您可以:

打印日志消息

使用 Kanzi 日志宏打印消息到日志。绝大多数日志宏使用固定日志级别显示消息中信息的严重性。请参阅 设置日志级别

建议

请勿在日志宏调用中使用应用程序关键代码。如果在日志宏调用中,将应用程序关键代码用作参数,且在编译过程中禁用分配给调用中的消息的日志级别或日志类别,预处理器会移除带有应用程序关键代码的日志宏调用。

Kanzi 提供以下日志宏:

日志宏 描述
kzLogError 日志错误消息,使用默认记录器 (DefaultLogger)、error (KZ_LOG_LEVEL_ERROR) 日志级别和您作为输入参数提供的日志类别。
kzLogWarning 日志警告消息,使用默认记录器 (DefaultLogger)、warning (KZ_LOG_LEVEL_WARNING) 日志级别和您作为输入参数提供的日志类别。
kzLogInfo 日志信息消息,使用默认记录器(DefaultLogger)、info (KZ_LOG_LEVEL_INFO) 日志级别和您作为输入参数提供的日志类别。
kzLogTrace 日志跟踪消息,使用默认记录器 (DefaultLogger)、trace (KZ_LOG_LEVEL_TRACE) 日志级别和您作为输入参数提供的日志类别。
kzLogDebug 日志调试消息,使用默认记录器 (DefaultLogger)、info (KZ_LOG_LEVEL_INFO) 日志级别和日志类别 KZ_LOG_CATEGORY_DEBUG
kzLog 日志消息,使用自定义记录器和您作为输入参数提供的日志级别和日志类别。请参阅创建自定义记录器
   

要打印日志消息:

  1. 在您的应用程序代码中,使用要打印日志消息的日志宏。
    例如:
  2. 构建和运行应用程序。请参阅部署 Kanzi 应用程序
    例如,在 Windows 中使用 GL_vs2015_Debug 构建配置在 Visual Studio 中构建您的应用程序。当运行应用程序且执行到调用日志宏的代码位置时,Kanzi 打印消息到调试控制台。

设置日志级别

使用日志等级来基于严重性显示日志消息。 例如,要记录应用程序执行过程中的关键问题,请使用 error 日志级别 (KZ_LOG_LEVEL_ERROR)。

Kanzi日志系统提供以下日志级别:

日志级别 名称 严重性 描述
KZ_LOG_LEVEL_ERROR error 1 记录关键故障消息。创建详细的错误消息,让用户能够接收到足够多的问题相关信息。
KZ_LOG_LEVEL_WARNING warning 2 记录需要引起注意但不必归为故障的事实。例如,通过警告消息,告知用户应用程序可以从中恢复的结果,例如缺失一个具有默认值的参数,或是一个可导致性能下降的事件(但不是故障)。
KZ_LOG_LEVEL_INFO info 3 记录概览系统当前情况,通过的日志状态数量,配置相关的静态信息,以及其他内容的相关信息。
KZ_LOG_LEVEL_TRACE trace 4 记录系统相关信息的最大数量。这是最为详细的日志级别。使用该级别可排除多种问题。
       

以下日志级别默认启用:

要设置日志级别,请使用 KZ_LOG_LEVEL_ENABLED_THRESHOLD 宏。
例如,要设置启用所有日志级别的日志级别:

#定义 KZ_LOG_LEVEL_ENABLED_THRESHOLD KZ_LOG_LEVEL_TRACE

您可以创建自己的日志级别。请参阅 KZ_LOG_CREATE_LEVEL

使用日志类别

使用日志类别对包含特定功能相关信息的消息进行分组。

Kanzi 日志系统提供以下默认日志类别:

日志类别 描述
KZ_LOG_CATEGORY_DEBUG 收集调试消息。
KZ_LOG_CATEGORY_GRAPHICS_MESH_EXTRA 收集图形网格日志消息。
KZ_LOG_CATEGORY_EGL_EXTRA 收集 EGL 日志消息。
KZ_LOG_CATEGORY_GENERIC 收集尚未分配任何其他日志类别的日志消息。推荐始终为每条日志消息明确分配以下其中一种日志类别,或创建新的日志类别。

要创建和使用日志类别,请执行以下代码:

  1. 使用 KZ_LOG_CREATE_CATEGORY 宏创建日志类别:
    //创建一个名为“My category”的日志类别,并将类别状态设置为启用。
    //Kanzi 日志系统使用类别状态过滤日志消息。
    //要禁用日志类别,请使用 KZ_LOG_DISABLED_CATEGORY。
    #定义 MY_LOG_CATEGORY    KZ_LOG_CREATE_CATEGORY(KZ_LOG_ENABLED_CATEGORY, "My category")
  2. 在创建的日志类别中打印一条日志消息:
    //使用 MY_LOG_CATEGORY 日志类别打印到日志 "这是一条信息消息。”
    kzLogInfo(MY_LOG_CATEGORY, ("这是一条信息消息。"));
  3. 构建和运行应用程序或在 Kanzi Studio 预览 (Preview) 中与应用程序互动。当应用程序执行到创建了日志消息的代码时,Kanzi 打印消息到调试控制台或 Kanzi Studio 日志 (Log) 窗口。
    info:My category> This is an info message.

创建自定义记录器

要重定向日志消息,您可以实现自定义记录器类(继承自 AbstractLogger),并向 Kanzi 日志系统推送自定义日志。让记录器类重写 AbstractLogger::writeOverride 函数。

要使用自定义记录器重写日志消息,请使用 kzLog 宏。

如果要使用自定义记录器写入所有应用程序日志消息,请在默认记录器 (DefaultLogger) 中注册记录器。默认记录器继承自 AbstractLogger,包含每条日志消息通过的一长串记录器。默认情况下,这些记录器已在默认记录器中注册。

默认记录器 日志消息目的地
CoutLogger 标准输出
AndroidLogger Android 系统日志
Win32DebugLogger Windows 系统中的 Kanzi 调试控制台

要实施记录器:

//使用此记录器将日志消息存储在容器中,用于日后检索。
//
//该类继承自 kanzi::AbstractLogger and implements the writeOverride() 函数。在容器中存储日志。
//要检索日志,使用 get() function.
class SimpleLogger : public AbstractLogger
{
public:
    //Kanzi 调用此函数将消息写入日志。
    //
    //此函数将日志消息存储在容器中。要检索所有日志消息,使用 get() 函数。
    //每条日志消息中包含:
    // - 消息文本 - 
    // - 日志级别 - 
    // - 日志类别 
    // - 如果某条消息为错误消息,则包括文件名和发生错误的所在行数 
    //
    // \参数等级 消息的日志等级。
    // \param levelName 该字符串代表日志等级。
    // \param categoryName 该字符串代表日志类别。
    // \param fileName 文件名(消息内容起始点)。
    // \param lineNumber 消息内容起始行。
    // \param message 消息内容。
    virtual void writeOverride(LogLevel level, string_view levelName, string_view categoryName,
                               string_view fileName, size_t lineNumber, string_view message)
    {
        //日志以级别名称开始。
        string logMessage(levelName);

        //用冒号分隔日志级别和日志类别。
        logMessage += ':';

        // 添加类别名称。
        logMessage.append(categoryName.data(), categoryName.length());

        if (level == LogLevelError)
        {
            // 已报告错误。
            // 要显示错误在代码中的报告位置,添加文件名和行数到消息中。
            logMessage.append(fileName.data(), fileName.length());

            // 用冒号分隔文件名和行数。
            logMessage += ':';
            logMessage += to_string(lineNumber);
        }

        // 添加尖括号和消息文本。
        logMessage += "> ";
        logMessage.append(message.data(), message.length());

        // 将日志消息附加到日志矢量。
        m_log.push_back(logMessage);
    }

    // 获得日志矢量参考。
    vector<string>& getLog()
    {
        return m_log;
    }

private:
    // 日志矢量。
    vector<string> m_log;
};

要以静态方式使用记录器,请实现以下操作:

// SimpleLogger 从 from kanzi 继承::AbstractLogger and implements writeOverride.
SimpleLogger simpleLogger;

//使用 SimpleLogger 编写日志消息。
kzLog(simpleLogger, KZ_LOG_LEVEL_INFO, KZ_LOG_CATEGORY_GENERIC, ("Lets log 1 + 2 = {}.", 1 + 2));

要使用记录器链中的记录器,请实现以下操作:

// SimpleLogger 从 from kanzi 继承::AbstractLogger and implements writeOverride.
AbstractLoggerUniquePtr simpleLogger(new SimpleLogger());

// 将 SimpleLogger 添加到记录器链前,将指针指向它。
//将 SimpleLogger 添加到记录器链后,记录器链控制 SimpleLogger 的寿命。
SimpleLogger* simpleLoggerPtr = static_cast<SimpleLogger*>(simpleLogger.get());

// 将 SimpleLogger 推向记录器链。现在,SimpleLogger 和其他记录器都有处理每一条日志消息。
DefaultLogger::pushLogger(kanzi::move(simpleLogger));

// 编写日志消息。SimpleLogger 处理该消息。
kzLogInfo(KZ_LOG_CATEGORY_GENERIC, ("Lets log 1 + 2 = {}.", 1 + 2));

要将记录器设置为处理所有日志消息,请实现以下操作:

// SimpleLogger 从 from kanzi 继承::AbstractLogger and implements writeOverride.
AbstractLoggerUniquePtr simpleLogger(new SimpleLogger());

// 将 SimpleLogger 添加到记录器链前,将指针指向它。
//将 SimpleLogger 添加到记录器链后,记录器链控制 SimpleLogger 的寿命。
SimpleLogger* simpleLoggerPtr = static_cast<SimpleLogger*>(simpleLogger.get());

// 移除记录器中所有默认记录器。
//这样,只有 SimpleLogger(稍后推送给链)处理日志消息。
DefaultLogger::popAllLoggers();

// 向记录器链推送 SimpleLogger。现在,只有 SimpleLogger 处理每一条日志消息。
DefaultLogger::pushLogger(kanzi::move(simpleLogger));

// 编写日志消息。SimpleLogger 处理该消息。
kzLogInfo(KZ_LOG_CATEGORY_GENERIC, ("Lets log 1 + 2 = {}.", 1 + 2));

另请参阅

最佳实践

测量应用程序性能

排除应用程序的性能问题

记录 Kanzi Engine 性能剖析数据

记录应用程序代码性能剖析数据

记录资源剖析数据